/*
 **********************************************************************
 * File name: vector.h
 *
 * COPYRIGHT (C) 2018-2022
 *
 * The license and distribution terms for this file may be found in 
 * the LICEMSE file.
 *
 * Author: ChenLong (Add new editor)
 * Email: worldlong@foxmail.com
 **********************************************************************
*/
#pragma once
/*
*/
#include <cmath>
#include <cstring>
#include "matrix.h"
/*
*/
namespace matrix
{
  
template<typename Type, size_t  M, size_t  N>
class Matrix;

template<typename Type, size_t M>
class SquareMatrix;

template<typename Type, size_t M>
class Vector : public Matrix<Type, 1, M>
{
public:
  Type* v = (Type*)this->data;
  /*
  */
  Vector() :
    Matrix<Type, 1, M>()
  {}
  
  Vector(Type data0) :
    Matrix<Type, 1, M>(data0)
  {}
  
  Vector(const Type *data0) :
    Matrix<Type, 1, M>(data0)
  {}
  
  Vector(const Vector<Type, M> &vb) :
    Matrix<Type, 1, M>(vb.data)
  {}

  /*------------------------------------------*
   * Operator overload                        *
   *------------------------------------------*/
  /*
   * V1 = V2
   */
  Vector<Type, M> &operator=(const Vector<Type, M> &vb)
  {
    if (this != &vb) {
      memcpy(this->data, vb.data, sizeof(this->data));
    }
    return (*this);
  }
  /*
   * V1 = M2
   */
  Vector<Type, M> &operator=(const Matrix<Type, 1, M> &vb)
  {
    if (this != &vb) {
      memcpy(this->data, vb.data, sizeof(this->data));
    }
    return (*this);
  }
 
  /*
   * V1 * V2
   */
  Vector<Type, M> operator*(const Vector<Type, M> &vb) const 
  {
    Vector<Type, M> vr;
    for (size_t i = 0; i<M; i++) {
        vr.v[i] = v[i] * vb.v[i];
    }
    return vr;
  }
  
  /*
   * V1 * M2
   */
  template<size_t N>
  Vector<Type, N> operator*(const Matrix<Type, M, N> &vb) const 
  {
    Vector<Type, N> vr;
    
    for (size_t j = 0; j < N; j++) {
      vr.v[j] = 0;
      for (size_t i = 0; i < M; i++) {
        vr.v[j] += v[i] * vb.data[i][j];
      }
    }
    return vr;
  }
  
  /*
   * V1 * S2
   */
  Vector<Type, M> operator*(Type scalar) const 
  {
    Vector<Type, M> vr;
    
    for (size_t i = 0; i < M; i++) {
        vr.v[i] = v[i] * scalar;
    }
    return vr;
  }

  /*------------------------------------------*
   * Functions                                *
   *------------------------------------------*/
  Type dot(const Vector<Type, M> &vb) const 
  {
    Type vr = 0;
    for (size_t i = 0; i < M; i++) {
        vr += v[i] * vb.v[i];
    }
    return vr;
  }
};


template<typename Type>
class Vector2 : public Vector<Type, 2>
{
public:
  /*
  */
  Type &x = this->data[0][0];
  Type &y = this->data[0][1];
  
  Vector2() :
    Vector<Type, 2>()
  {
  }
  
  Vector2(Type data0) :
    Vector<Type, 2>(data0)
  {
  }
  
  Vector2(Type x0, Type y0) :
    Vector<Type, 2>()
  {
    x = x0;
    y = y0;
  }
  
  Vector2(const Vector2<Type> &vb) :
    Vector<Type, 2>(vb)
  {
  }
  
  Vector2(const Vector<Type, 2> &vb) :
    Vector<Type, 2>(vb)
  {
  }
  
  Vector2(const Matrix<Type, 1, 2> &vb) :
    Vector<Type, 2>()
  {
    x = vb.data[0][0];
    y = vb.data[0][1];
  }
  
  /*
   * V1 = V2
   */
  Vector2<Type> &operator=(const Vector2<Type> &vb)
  {
    if (this != &vb) {
      x = vb.x;
      y = vb.y;
    }
    return (*this);
  }
  
  /*
   * V1 = V2
   */
  Vector2<Type> &operator=(const Vector<Type, 2> &vb)
  {
    if (this != &vb) {
      x = vb.data[0][0];
      y = vb.data[0][1];
    }
    return (*this);
  }
  
  /*
   * V1 = V2
   */
  Vector2<Type> &operator=(const Matrix<Type, 1, 2> &vb)
  {
    if (this != &vb) {
      x = vb.data[0][0];
      y = vb.data[0][1];
    }
    return (*this);
  }
};



template<typename Type>
class Vector3 : public Vector<Type, 3>
{
public:
  /*
  */
  Type &x = this->data[0][0];
  Type &y = this->data[0][1];
  Type &z = this->data[0][2];
  
  Vector3() :
    Vector<Type, 3>()
  {
  }
  
  Vector3(Type data0) :
    Vector<Type, 3>(data0)
  {
  }
  
  Vector3(Type x0, Type y0, Type z0) :
    Vector<Type, 3>()
  {
    x = x0;
    y = y0;
    z = z0;
  }
  
  Vector3(const Vector3<Type> &vb) :
    Vector<Type, 3>(vb)
  {
  }
  
  Vector3(const Vector<Type, 3> &vb) :
    Vector<Type, 3>(vb)
  {
  }
  
  Vector3(const Matrix<Type, 1, 3> &vb) :
    Vector<Type, 3>()
  {
    x = vb.data[0][0];
    y = vb.data[0][1];
    z = vb.data[0][2];
  }
  
  /*
   * V1 = V2
   */
  Vector3<Type> &operator=(const Vector3<Type> &vb)
  {
    if (this != &vb) {
      memcpy(this->data, vb.data, sizeof(this->data));
    }
    return (*this);
  }
  
  /*
   * V1 = V2
   */
  Vector3<Type> &operator=(const Vector<Type, 3> &vb)
  {
    if (this != &vb) {
      x = vb.data[0][0];
      y = vb.data[0][1];
      z = vb.data[0][2];
    }
    return (*this);
  }
  
  /*
   * V1 = V2
   */
  Vector3<Type> &operator=(const Matrix<Type, 1, 3> &vb)
  {
    if (this != &vb) {
      x = vb.data[0][0];
      y = vb.data[0][1];
      z = vb.data[0][2];
    }
    return (*this);
  }
  
  /*------------------------------------------*
   * Functions                                *
   *------------------------------------------*/
  SquareMatrix<Type, 3> skew_symmetric(Type scalar) const
  {
    SquareMatrix<Type, 3> vr;
    
    vr.data[0][0] = 0;
    vr.data[0][1] =-z*scalar;
    vr.data[0][2] = y*scalar;
    
    vr.data[1][0] =-vr.data[0][1];
    vr.data[1][1] = 0;
    vr.data[1][2] =-x*scalar;
    
    vr.data[2][0] =-vr.data[0][2];
    vr.data[2][1] =-vr.data[1][2];
    vr.data[2][2] = 0;
    
    return vr;
  }
  
  inline SquareMatrix<Type, 3> skew_symmetric() const
  {
    return skew_symmetric(1.0f);
  }
  
  Vector3<Type> cross(const Vector3<Type> &vb) const
  {
    Vector3<Type> vr;
    vr.x = y*vb.z - z*vb.y;
    vr.y = z*vb.x - x*vb.z;
    vr.z = x*vb.y - y*vb.x;
    return vr;
  }
};

typedef Vector2<float> Vector2f;
typedef Vector3<float> Vector3f;
typedef Vector<float, 4> Vector4f;
typedef Vector<float, 5> Vector5f;
typedef Vector<float, 6> Vector6f;

}


